﻿using System;
using System.Collections.Generic;
using TripleA.Core.Interfaces;
using System.Linq;

namespace TripleA.Core.Pipeline
{
    /// <summary>
    /// This version of the pipeline config will execute the step immediately as it is
    /// added to the pipeline - this is suited for BDD style test frameworks where the 
    /// BDD itself works a pipeline (Given/When/Then).
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class BddPipelineConfig<T> : IPipelineConfig<T>
    {
        private readonly T _context;
        private readonly List<IPipelineStep<T>> _steps;
        private readonly Action<string> _dumper;

        public BddPipelineConfig(T context)
        {
            _context = context;
            _steps = new List<IPipelineStep<T>>();
            _dumper = Dump;
        }

        public BddPipelineConfig(T context, Action<string> dumpAction)
        {
            _context = context;
            _steps = new List<IPipelineStep<T>>();
            _dumper = dumpAction;
        }

        private static void Dump(string stepResult)
        {
            Console.WriteLine(stepResult);
        }

        public IEnumerable<IPipelineStep<T>> Steps
        {
            get { return _steps; }
        }

        public IPipelineConfig<T> RunStep(IPipelineStep<T> step)
        {
            Run(step);            
            return this;
        }

        public IPipelineConfig<T> RunSteps(IEnumerable<IPipelineStep<T>> steps)
        {
            if (steps == null)
                return this;
            Run(steps.ToArray());
            return this;
        }

        protected void Run(params IPipelineStep<T>[] steps)
        {
            _steps.AddRange(steps);

            var pipeline = new DefaultPipeline<T>(new PipelineConfig<T>(steps));
            var result = pipeline.Execute(_context);
            result.Dump(_dumper);

            if (!result.Success)
                throw new AggregateException("Errors!",
                    result.StepResults.Where(sr => sr.Failure != null && sr.Failure.Error != null).Select(sr => sr.Failure.Error));
        }
    }
}